#include "../include/server.h"

#define LOCAL_IP      "0.0.0.0"
#define LOCAL_PORT    ((uint16_t)10126)

#define debug(...)                                     \
do                             \
{                              \
printf(__VA_ARGS__);       \
fflush(stdout);            \
}while(0)

void *handleClient(void *arg) {
    SOCKET newsock = *(SOCKET *) arg;
    int nrecv = 0;
    char buf[512];

    while (true) {
        if ((nrecv = recv(newsock, buf, sizeof(buf), 0)) <= 0)
            break;

        if (strncmp(buf, "quit", 4) == 0)
            break;


        if (send(newsock, buf, nrecv, 0) < 0) {
            break;
        } else {
            debug(" accept %s \r\n", buf);
        }
        //清除buf
        memset(buf, 0X00, sizeof(buf));
    }
    try {
        closesocket(newsock);
        free(arg);
    } catch (...) {
        debug("closesocket \r\n");
    }

    debug("disconnected\r\n");

    return nullptr;
}

int startTcpServer() {
    int ret = 0;
    WSADATA ws;
    SOCKET sock;
    struct sockaddr_in local{};


    int addrlen = 0;


    if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) {
        ret = -1;
        goto __exit;
    }

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        ret = -2;
        goto __exit;
    }

    local.sin_family = AF_INET;
    local.sin_addr.S_un.S_addr = inet_addr(LOCAL_IP);
    local.sin_port = htons(LOCAL_PORT);
    memset(local.sin_zero, 0X00, sizeof(local.sin_zero));

    if (bind(sock, (const struct sockaddr *) &local, sizeof(local)) == SOCKET_ERROR) {
        ret = -3;
        goto __exit;
    }

    listen(sock, 5);

    addrlen = sizeof(local);

    debug(" accept %s:%d...\r\n", LOCAL_IP, LOCAL_PORT);

    while (true) {
        SOCKET newsock;
        sockaddr_in client{};

        if ((newsock = accept(sock, (struct sockaddr *) &client, &addrlen)) == SOCKET_ERROR) {
            debug(" accept error \r\n");
            ret = -4;
            goto __exit;
        }

        debug(" %s:%d connected\r\n", inet_ntoa(client.sin_addr), client.sin_port);

        pthread_t tid;
        SOCKET *client_sock = (SOCKET *) malloc(sizeof(SOCKET));
        *client_sock = newsock;
        int res = pthread_create(&tid, nullptr, handleClient, (void *) client_sock);
        if (res != 0) {
            debug(" pthread_create error %d \r\n", res);
            ret = -5;
            goto __exit;
        }
        pthread_detach(tid);
    }


__exit:
    debug("exit %d \r\n", ret);
    closesocket(sock);
    return ret;
}
